﻿using Microsoft.Hadoop.WebHDFS;
using Microsoft.Hadoop.WebHDFS.Adapters;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using ViewMaker;
using ViewMaker.Core;
using ViewMaker.Core.Controls;

namespace HDInsightStudio
{
    [View(typeof(HdfsStudioView))]
    [ViewProperty(ViewControl.Properties.WindowHeight, 600)]
    [ViewProperty(ViewControl.Properties.WindowWidth, 800)]
    public class HdfsStudio : ViewModelBase
    {
        public class HdfsStudioInput : ViewModelBase
        {
            HdfsStudio parent;

            public string Input { get; set;}


            public HdfsStudioInput(HdfsStudio parent)
            {
                this.parent = parent;
                Input = parent.Input;
            }

            public ICommand OKCommand
            {
                get
                {
                    return CreateCommand(() =>
                    {
                        parent.Input = Input;
                        ExecuteViewCommand(ViewCommands.Close);
                    });
                }
            }

            public ICommand CancelCommand
            {
                get
                {
                    return CreateCommand(() =>
                    {
                        ExecuteViewCommand(ViewCommands.Close);
                    });
                }
            }
        }

        public HdInsightConfig Config { get; private set; }

        [View(ViewControlType.TreeView)]
        [ViewProperty(TreeViewControl.Properties.DisplayMember, "Name")]
        [ViewProperty(TreeViewControl.Properties.ItemsSource, "Children")]
        [ViewProperty(TreeViewControl.Properties.IsExpanded, "IsExpanded")]
        [ViewProperty(TreeViewControl.Properties.IsSelected, "IsSelected")]
        [ViewProperty(TreeViewControl.Properties.SelectedItemChangedCommand, "SelectedItemChangedCommand")]
        public ObservableCollection<TreeItem> Children { get; private set; }
        private FolderItem _root;

        public FolderItem CurrentItem { get; set; }

        public ObservableCollection<FileItem> Files
        {
            get { return _files; }
            set { _files = value; OnPropertyChanged("Files"); }
        }
        private ObservableCollection<FileItem> _files;

        public string Input { get; set; }
        public string ContentEncoding {get; set;}

        public HdfsStudio()
        {
            Config = HdInsightConfig.Instance;
            _root = new FolderItem(null, "/", Config.HdfsClient);
            if (_root != null)
            {
                _root.GetFolderStatus();
                Children = _root.Children;
            }
            

        }


        [Browsable(false)]
        public ICommand SelectedItemChangedCommand
        {
            get { return this.CreateCommand(GenerateContent); }
        }
        private void GenerateContent(object arg)
        {
            var content = arg as FolderItem;
            if (content != null)
            {
                content.GetFolderStatus();
                content.IsExpanded = true;
                Files = content.Files;
            }
            this.CurrentItem = content;
        }


        public ICommand ConnectCommand
        {
            get
            {
                return this.CreateCommand(() =>
                {
                    HdInsightConfig.Instance.Setup();
                });
            }
        }

        public ICommand DownloadCommand
        {
            get { return this.CreateCommand(Download); }
        }
        private async void Download(object targetObject)
        {
            var target = (FileItem)targetObject;

            if (target != null)
            {
                var dialog = new SaveFileDialog();
                dialog.Filter = "*.*|*.*";
                dialog.FileName = target.Name;
                if (dialog.ShowDialog() == true)
                {
                    await DownloadItem(dialog.FileName, target.Path);
                }
            }
        }

        private async Task DownloadItem(string filename, string itemPath)
        {
            using (var target = new FileStream(filename, FileMode.Create, FileAccess.Write))
            {
                var message = await Config.HdfsClient.OpenFile(itemPath);
                using (var source = await message.Content.ReadAsStreamAsync())
                {
                    Byte[] buff = new Byte[1024 * 1024];
                    while (true)
                    {
                        var size = await source.ReadAsync(buff, 0, buff.Length);
                        if (size <= 0) break;
                        await target.WriteAsync(buff, 0, size);
                    }
                }
            }
        }

        public ICommand UploadCommand
        {
            get { return this.CreateCommand(Upload); }
        }
        private async void Upload()
        {
            if (CurrentItem != null)
            {
                var dialog = new OpenFileDialog();
                dialog.Filter = "*.*|*.*";
                dialog.Multiselect = true;
                if (dialog.ShowDialog() == true)
                {
                    foreach (var item in dialog.FileNames)
                    {
                        using (var source = new FileStream(item, FileMode.Open, FileAccess.Read))
                        {
                            string targetPath = CurrentItem.Path + "/" + Path.GetFileName(item);
                            await Config.HdfsClient.CreateFile(item, targetPath);
                        }
                    }
                    CurrentItem.GetFolderStatus(true);
                }
            }
        }

        public ICommand DeleteFolderCommand
        {
            get { return this.CreateCommand(DeleteFolderItem); }
        }
        public ICommand DeleteItemCommand
        {
            get { return this.CreateCommand(DeleteFileItem); }
        }


 
         private void DeleteFolderItem()
        {
            var target = CurrentItem;
            BackgroundWorker worker = new BackgroundWorker();

            if (CurrentItem != null)
            {
                worker.DoWork += (s, e) =>
                {
                    Config.HdfsClient.DeleteDirectory(target.Path, true);
                };
                worker.RunWorkerCompleted += (s, e) =>
                {
                    ((FolderItem)target.Parent).Children.Remove(target);
                };
                worker.RunWorkerAsync();
            }

        }

        private void DeleteFileItem(object targetObject)
        {
            var target = (FileItem)targetObject;
            BackgroundWorker worker = new BackgroundWorker();


            if (CurrentItem != null)
            {
                worker.DoWork += (s, e) =>
                {
                    Config.HdfsClient.DeleteDirectory(target.Path, true);
                };
                worker.RunWorkerCompleted += (s, e) =>
                {
                    var parent = ((FolderItem)target.Parent);
                    parent.Files.Remove(target);
                };
                worker.RunWorkerAsync();
            }

        }


        public ICommand CreateDirectoryCommand
        {
            get { return this.CreateCommand(async () => await CreateDirectory()); }
        }
        private async Task CreateDirectory()
        {
            if (CurrentItem != null)
            {
                Input = null;
                ViewUtil.ShowDialog(new HdfsStudioInput(this));
                if (!string.IsNullOrEmpty(Input))
                {
                    await Config.HdfsClient.CreateDirectory(CurrentItem.Path + "/" + Input);
                }
                ((FolderItem)CurrentItem).GetFolderStatus(true);
            }
        }

        public ICommand ViewCommand
        {
            get { return this.CreateCommand(async ()=> await View()); }
        }
        private async Task View()
        {
            if (CurrentItem != null && CurrentItem.CurrentItem != null)
            {
                using (var st = new MemoryStream())
                {
                    var message = await Config.HdfsClient.OpenFile(CurrentItem.CurrentItem.Path, 0, 1000 * 1000 * 2);
                    using (var source = await message.Content.ReadAsStreamAsync())
                    {
                        Byte[] buff = new Byte[1024 * 1024];
                        while (true)
                        {
                            var size = await source.ReadAsync(buff, 0, buff.Length);
                            if (size <= 0) break;
                            st.Write(buff, 0, size);
                        }
                        Encoding enc = Encoding.GetEncoding(    ContentEncoding ?? "ASCII");
                        int i;
                        for (i = 0; i < buff.Length; i++)
                        {
                            if (buff[i] == 0) break; 
                        }
                        string txt = enc.GetString(buff, 0, i);
                        var txtVM = new TextViewModel();
                        txtVM.Text = txt;
                        ViewUtil.Show(txtVM);
                    }
                }
            }
        }
        public ICommand UpdateCommand
        {
            get { return this.CreateCommand(Update); }
        }
        private  void Update()
        {
            if (CurrentItem != null)
            {
                if (CurrentItem != null) CurrentItem.GetFolderStatus(true);
            }

        }

        public ICommand ModifyConfigCommand
        {
            get { return this.CreateCommand(() => { ViewUtil.ShowDialog(Config); }); }
        }

        public ICommand MapReduceCommand
        {
            get { return this.CreateCommand(() => { ViewUtil.Show(new MapReduceStudio()); }); }
        }
        public ICommand JarMapReduceCommand
        {
            get { return this.CreateCommand(() => { ViewUtil.Show(new JarMapReduceStudio()); }); }
        }
        public ICommand HiveCommand
        {
            get { return this.CreateCommand(() => { ViewUtil.Show(new HiveStudio()); }); }
        }
        public ICommand SqoopCommand
        {
            get { return this.CreateCommand(() => { ViewUtil.Show(new SqoopStudio()); }); }
        }
        public ICommand CloseCommand
        {
            get { return this.CreateViewCommand(ViewCommands.Close); }
        }
    }
}
